/**
 * OpenLayers工具包
 */
var OpenLayersUtil = {
    /****************************************** 基础参数 START *********************************************************/
    /**
     * 地图对象
     */
    map: null,
    /**
     * 坐标系类型(默认EPSG:3857)
     */
    coordinateSystems: ['EPSG:3857', 'EPSG:4326'],
    coordinateDefault: 'EPSG:4326',
    /**
     * 默认位置
     */
    defaultLocation: [112.46261468487126, 34.66450747066452],
    /**
     * 天地图请求密钥
     */
    tk: "b5c6d22f3ea7a78d2526bcc2552882ef",//"49ea1deec0ffd88ef13a3f69987e9a63",
    /**
     * 天地图请求地址创建
     * @param tk
     * @param type
     * @returns {string}
     */
    getTiandituUrl: function (type){
        return "http://t{0-6}.tianditu.com/DataServer?x={x}&y={y}&l={z}&tk=" + this.tk + "&T=" + type
    },
    /**
     * 获取地图底图
     * @param type vec_w：天地图路网 img_w：天地图卫星影像 cva_w：天地图文字标注
     * @param title 标题
     * @returns {ol.layer.Tile}
     */
    findBaseMap: function (type,title){
        const thas = this;
        const opt = {
            source: new ol.source.XYZ({
                url: thas.getTiandituUrl(type)
            })
        };
        if (title) {
            opt.title = title;
        }
        return new ol.layer.Tile(opt);
    },
    /**
     * 图层集合
     */
    layers: {
        "OSM": new ol.layer.Tile({
            title: 'OSM',
            source: new ol.source.OSM()
        }),
        "天地图路网": function (){
            return OpenLayersUtil.findBaseMap("vec_w","天地图路网");
        },
        "天地图卫星影像": function (){
            return OpenLayersUtil.findBaseMap("img_w","天地图卫星影像");
        },
        "天地图文字标注": function (){
            return OpenLayersUtil.findBaseMap("cva_w","天地图文字标注");
        },
    },

    /**
     * 默认样式
     */
    styles: {
        // 字符串
        string: new ol.style.Style({
            text: new ol.style.Text({
                text: '字符串',
                font: 'bold 26px normal',
                textAlign: "center",
                textBaseline: "middle",
                fill: new ol.style.Fill({
                    color: "#000000"
                }),
            })
        }),
        // 点
        point: new ol.style.Style({
            image: new ol.style.Circle({
                radius: 10,
                fill: new ol.style.Fill({
                    color: '#ab13de'
                })
            }),
            text: new ol.style.Text({
                text: "点",
                /*fill: new ol.style.Fill({
                  color: '#fff'
                }),*/
                font: "bold 30px normal",// "18px",
                // 文本对齐方向，以线的中心点为基准。 'left', 'right', 'center', 'end' or 'start'. Default is 'center'.
                textAlign: "center",
                // 文本底部对齐方向，以线为基准。 'bottom', 'top', 'middle', 'alphabetic', 'hanging', 'ideographic'.
                textBaseline: "middle",
                offsetX: 0,
                offsetY: -12,
                fill: new ol.style.Fill({
                    color: "#000000"
                }),
                stroke: new ol.style.Stroke({
                    color: '#ab13de',
                    width: 2
                })
            })
        }),
        // 线
        line: new ol.style.Style({
            stroke: new ol.style.Stroke({
                color: 'blue',
                width: 5
            })
        }),
        // 面
        polygon: new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'pink'
            })
        }),
        // 圆
        round: new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'orange'
            })
        }),
        // 圆圈
        circle: new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'rgba(255, 0, 0, 0.2)'
            }),
            stroke: new ol.style.Stroke({
                color: '#ffcc33',
                width: 2
            }),
            image: new ol.style.Circle({
                radius: 7,
                fill: new ol.style.Fill({
                    color: '#ffcc33'
                })
            })
        }),
        // 图片
        image: new ol.style.Style({
            image: new ol.style.Icon({
                // src: 'images/point.png'
                // src: 'images/WYLD.png'
                src: 'images/zx.png',
                // 旋转 =（方位角 / 180 ）* Math.PI
                rotation: 1.5 * Math.PI,
                // 设置图片的宽度和高度
                // size: [100, 100]
            })
        }),
        // json
        json: function(feature) {
            // console.log("feature",feature);
            return new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: "#3601bd",//通过要素拿到具体的值
                    width: 2,
                    opacity: 1
                }),
                fill: new ol.style.Fill({
                    color: "rgba(255,255,255,0)",
                    opacity: 0
                }),
                text: new ol.style.Text({
                    text: feature.N.name,
                    font: '12px bold serif',
                    fill: new ol.style.Fill({
                        color: '#000'
                    }),
                    stroke: new ol.style.Stroke({
                        color: '#fff',
                        width: 2
                    })
                })
            })
        }
    },
    /**
     * 绘制对象ol.Interaction.Draw
     */
    draw: null,
    /****************************************** 基础参数 END   *********************************************************/
    /**
     * 初始化
     * @param id
     * @returns {*}
     */
    init(id){
        const thas = this;
        // 创建map对象
        this.map = new ol.Map({
            // 容器
            target: id,
            // 图层集合(数组可以放置多个)
            layers: [
                // 创建第一个图层，也是地图底图
                OpenLayersUtil.layers.天地图卫星影像()
            ],
            // 同时加载的最大瓦片数(默认为16)
            maxTilesLoading: 16,
            // 视图
            view: new ol.View({
                /*constrainRotation: 90,
                enableRotation: true,*/
                // 限制视图的范围，换句话说，超出此范围的任何内容都无法在地图上看到
                // extent:[120,30,140,50],
                // 坐标系（默认：EPSG:3857）
                projection: thas.coordinateDefault,
                // 初始位置(经纬度转墨卡托)
                // center: this.wgs84ToMercator(this.defaultLocation),
                center: this.defaultLocation,
                // 初始大小
                zoom: 7,
                //最小缩放级别
                minZoom: 1,
                //最大缩放级别
                maxZoom: 15,
            }),
        })
        return this.map;
    },
    /**
     * 墨卡托（EPSG:3857）转换 WGS-84(EPSG:4326)
     * @param mercator
     * @returns {{x: number, y: number}}
     */
    mercatorToWgs84(mercator){
        return ol.proj.transform(mercator,'EPSG:3857', 'EPSG:4326');
    },
    /**
     * WGS-84(EPSG:4326)转换墨卡托（EPSG:3857）
     * @param lonlat
     * @returns {{x: number, y: number}}
     */
    wgs84ToMercator(lonlat){
        // 或者 ol.proj.fromLonLat([112.46261468487126, 34.66450747066452])
        return ol.proj.transform(lonlat, 'EPSG:4326', 'EPSG:3857');
    },
    /**
     * 鼠标位置控制
     * @param targetId 容器ID
     * @param projection 坐标系（默认EPSG:4326）
     * @param coordinateFormatTemplate 坐标格式模板
     * @param map
     */
    addMousePosition(targetId,projection,coordinateFormatTemplate,map){
        map = map == null ? this.map : map;
        // 设置坐标系
        projection = projection ? projection : 'EPSG:4326';
        // 设置坐标格式
        var coordinateFormat = null;
        if(coordinateFormatTemplate == null || coordinateFormatTemplate === ''){
            // 投影坐标格式：显示小数点后面多少位小数
            coordinateFormat = ol.coordinate.createStringXY(5)
        }else {
            coordinateFormat = function (coordinate) {
                // coordinateFormatTemplate 示例 ： '经度:{x} 纬度:{y}'
                return ol.coordinate.format(coordinate, coordinateFormatTemplate, 2);
            }
        }
        //鼠标获取坐标控件
        const mousePositionControl = new ol.control.MousePosition({
            // 投影坐标格式
            coordinateFormat: coordinateFormat,
            // 投影坐标系
            projection: projection,
            // 目标容器（没有容器默认右上角）
            target: document.getElementById(targetId),
            // 坐标信息显示样式
            className: 'custom-mouse-position',
            // 未定义坐标的标记
            undefinedHTML: ' '
        })
        // 添加控件到地图
        map.addControl(mousePositionControl)
    },
    /**
     * 监听鼠标移动事件，鼠标移动到feature区域时变为手形
     * @param map
     */
    addPointermove(map){
        map = map == null ? this.map : map;
        map.on('pointermove', function (e) {
            var pixel = map.getEventPixel(e.originalEvent);
            var hit = map.hasFeatureAtPixel(pixel);
            map.getTargetElement().style.cursor = hit ? 'pointer' : '';
        });
    },
    /**
     * 定位
     * @param lon
     * @param lat
     * @param zoom
     * @param map
     */
    setLocation(lon, lat, zoom, map){
        map = map == null ? this.map : map;
        map.getView().setCenter(this.wgs84ToMercator([ lon, lat]));
        if(zoom){
            map.getView().setZoom(zoom);
        }
    },
    /**
     * 开启点击图层弹出窗口
     * @param map
     */
    popupOpen(map){
        map = map == null ? this.map : map;
        // 1.在body加入挂载文本,同时加入OLPopup.css样式
        $('body').append(`<div id="popup" class="ol-popup">
            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
            <div id="popup-content"></div>
        </div>`);
        // 2.获取popup的dom对象
        var container = document.getElementById('popup');
        var content = document.getElementById('popup-content');
        var closer = document.getElementById('popup-closer');
        // 3.创建popup,将popup加入地图
        var popup = new ol.Overlay({
            element: container,
            autoPan: true,
            positioning: 'bottom-center',
            stopEvent: false,
            autoPanAnimation: {
                duration: 250
            }
        });
        map.addOverlay(popup);
        // 4.关闭popup事件
        closer.onclick = function () {
            popup.setPosition(undefined);
            closer.blur();
            return false;
        };
        // 5.监听鼠标单击事件，点击feature后弹出popup
        map.on('click', function (e) {
            // 5.1获取鼠标坐标
            var coordinate = e.coordinate;
            // 5.2判断鼠标当前位置是否存在Feature图层对象
            var feature = map.forEachFeatureAtPixel(e.pixel,
                function (feature, layer) {
                return feature;
            });
            if (feature) {
                // 清空html
                content.innerHTML = '';
                var keys = Object.keys(feature.N);
                for (let key of keys) {
                    console.log(key);
                }

                // 城市名称
                var cityName = document.createElement('h2');
                cityName.innerText = '文本';
                content.appendChild(cityName);

                // 弹出popup
                popup.setPosition(coordinate);
            }else {
                popup.setPosition(undefined);
                closer.blur();
            }
        });
    },
    /**
     * 绘制图层
     * @param type 类型 （None-无,Point-点,LineString-线,Polygon-多边形,Circle-圆,Square-正方形,Box-长方形）
     * @param source
     * @param map
     */
    addInteraction(type,source,style,map){
        map = map == null ? this.map : map;
        this.removeInteraction();
        if (source == null) {
            source = new ol.source.Vector();
        }
        if (style == null) {
            style = new ol.style.Style({
                // 填充样式
                fill: new ol.style.Fill({
                    color: 'rgba(255, 255, 255, 0.2)'
                }),
                // 线样式
                stroke: new ol.style.Stroke({
                    color: '#ffcc33',
                    width: 2
                }),
                // 点样式
                image: new ol.style.Circle({
                    radius: 7,
                    fill: new ol.style.Fill({
                        color: '#ffcc33'
                    })
                })
            });
        }
        // 实例化一个矢量图层Vector作为绘制层
        var vectorLayer = new ol.layer.Vector({
            source: source,
            style: style
        });
        // 将绘制层添加到地图容器中
        map.addLayer(vectorLayer);
        // 绘制类型
        if(type == 'None') {
            // 清空绘制的图形
            source.clear();
            return;
        }
        var geometryFunction, maxPoints;
        if(type === 'Square'){ //正方形
            // 设置绘制类型为Circle
            type = 'Circle';
            // 设置几何信息变更函数，即创建正方形
            geometryFunction = ol.interaction.Draw.createRegularPolygon(4);
        }else if(type === 'Box'){// 长方形(5.0以上版本失效)
            // 设置绘制类型为LineString
            type = 'LineString';
            // 设置最大点数为2
            maxPoints = 2;
            //设置几何信息变更函数，即设置长方形的坐标点
            geometryFunction = function(coordinates, geometry){
                if(!geometry){ // !geometry  意思是如果没有geometry则...
                    // 多边形
                    geometry = new ol.geom.Polygon(null);
                }
                //设置起始点及终止点
                var start = coordinates[0];
                var end = coordinates[1];
                //特别注意，长方形终止点与起始点重合
                geometry.setCoordinates([
                    [
                        start,
                        [start[0], end[1]],
                        end,
                        [end[0], start[1]],
                        start
                    ]
                ]);
                return geometry;
            };
        }

        //实例化图形绘制控件对象并添加到地图容器中
        this.draw = new ol.interaction.Draw({
            source: source,
            // 几何图形类型
            type: type,
            // 几何信息变更时的回调函数
            geometryFunction: geometryFunction,
            // 最大点数
            maxPoints: maxPoints
        });


        // 给画笔添加绘制开始函数
        this.draw.on("drawstart", function (evt) {
            source.clear();
        });
        // 给画笔添加结束绘制函数
        this.draw.on("drawend", function (evt) {
            // 坐标赋值
            console.log(evt.feature.getGeometry());
            // console.log(evt.feature.getGeometry().getCoordinates())
        });
        // 将画笔添加到地图上
        map.addInteraction(this.draw);
    },

    /**
     * 移除绘制图形控件
     */
    removeInteraction(){
        this.map.removeInteraction(this.draw);
    },

    /****************************************** 创建图层 START *********************************************************/
    /**
     * 创建数据源
     * @returns {ol.source.Vector}
     */
    createSource(){
        return new ol.source.Vector({
            wrapX: false,
            // 跨域
            crossOrigin: 'anonymous'
        });
    },
    /**
     * 创建图层
     * @param source
     * @param name
     * @param style
     * @param zIndex
     * @returns {ol.layer.Vector}
     */
    createLayer(source,name,style,zIndex){
        var layer = new ol.layer.Vector();
        if (name) {
            layer['name'] = name
        }
        if(source){
            layer.setSource(source)
        }
        if(style){
            layer.setStyle(style)
        }
        if (zIndex){
            layer.setZIndex(zIndex)
        }
        return layer;
    },
    /**
     * 创建样式
     * @param image
     * @param text
     * @param stroke
     * @param fill
     * @param geometry
     * @param renderer
     * @param zIndex
     * @returns {ol.style.Style}
     */
    createStyle(image,text,stroke,fill,geometry,renderer,zIndex){
        var style = new ol.style.Style();
        if (image) {
            style.setImage(image);
        }
        if (text) {
            style.setText(text);
        }
        if (stroke) {
            style.setStroke(stroke)
        }
        if (fill) {
            style.setFill(fill);
        }
        if (geometry) {
            style.setGeometry(geometry);
        }
        if (renderer) {
            style.setRenderer(renderer);
        }
        if (zIndex) {
            style.setZIndex(zIndex);
        }
        return style;
    },
    /**
     * 添加图层
     * @param layer
     */
    addLayer(layer,map){
        map = map == null ? this.map : map;
        map.addLayer(layer)
    },
    /**
     * 删除所有的图层
     * @param map
     */
    removeLayerAll(map){
        map = map == null ? this.map : map;
        var layers = map.getLayers();
        if (layers) {
            const layersArr = layers.getArray();
            const length = layers.getLength();
            for (var i = 0; i < length; i++) {
                map.removeLayer(layersArr[0]);
            }
        }
    },
    /**
     * 根据图层名或属性删除图层
     * @param layerName 图层名
     * @param name 属性名，默认name
     */
    removeLayerByLayerName(layerName,name,map) {
        if(layerName === null || layerName === ''){
            return;
        }
        map = map == null ? this.map : map;
        name = name == null ? "name" : name;
        // 获取图层集合
        var layers = map.getLayers();
        if (layers) {
            // 获取图层集合
            var layersArr = layers.getArray();
            for (var i = 0; i < layers.getLength(); i++) {
                var ln = layersArr[i];
                if (ln[name] === layerName) {
                    map.removeLayer(ln);
                }
            }
        }
    },
    /**
     * 按比例调整图片的大小
     * @param iconStyle
     * @param scale
     */
    setIconImageScale(iconStyle,scale){
        // 克隆原有图像实例
        const originalImage = iconStyle.getImage();
        // 克隆原有图像实例
        const scaledImage = originalImage.clone();
        // 设置新的缩放比例，例如将大小减半
        scaledImage.setScale(scale);
        // 设置新的图像实例到样式中
        iconStyle.setImage(scaledImage);
    },
    /****************************************** 创建图层 END ***********************************************************/

    /****************************************** 绘制图像 START *********************************************************/
    /**
     * 创建特征
     * @returns {ol.Feature}
     */
    createFeature(){
        return new ol.Feature()
    },
    setGeometryAndStyle(source,geometry,style){
        var feature = this.createFeature();
        feature.setGeometry(geometry)
        feature.setStyle(style);
        source.addFeature(feature);
    },
    /**
     * 绘制文字
     * @param source
     * @param lon
     * @param lat
     * @param text
     * @param font
     */
    drawText: function (source,lon, lat, text, style){
        // 样式
        if (!style) {
            style = this.styles.string
        }
        if (text) {
            style.getText().setText(text)
        }
        // 创建要素，设置其样式
        var geometry = new ol.geom.Point([lon, lat]);
        this.setGeometryAndStyle(source,geometry,style);
    },
    /**
     * 绘制点
     * @param source
     * @param lon
     * @param lat
     * @param style
     */
    drawPoint(source,lon, lat,style){
        if (!style) {
            style = this.styles.point
        }
        // 创建要素，设置其样式
        var geometry = new ol.geom.Point([lon, lat]);
        this.setGeometryAndStyle(source,geometry,style);
    },
    /**
     * 绘制线
     * @param source
     * @param lineData
     * @param style
     */
    drawLine(source,lineData,style){
        if (!style) {
            style = this.styles.line
        }
        // 创建要素，设置其样式
        var geometry = new ol.geom.LineString(lineData);
        this.setGeometryAndStyle(source,geometry,style);
    },
    /**
     * 绘制面
     * @param source
     * @param polygonData
     * @param style
     */
    drawPolygon(source,polygonData,style){
        if (!style) {
            style = this.styles.polygon
        }
        // 创建要素，设置其样式
        var geometry = new ol.geom.Polygon(polygonData);
        this.setGeometryAndStyle(source,geometry,style);
    },
    /**
     * 绘制圆
     * @param source
     * @param lon
     * @param lat
     * @param radius
     * @param style
     */
    drawRound(source,lon, lat,radius,style){
        if (!style) {
            style = this.styles.round
        }
        // 创建要素，设置其样式
        /*// 适应地图的圆
        var geometry = new ol.geom.Polygon.circular(new ol.Sphere(6378137)
            , [lon, lat], radius, 64);*/
        var geometry = new ol.geom.Circle([lon, lat], radius);
        this.setGeometryAndStyle(source,geometry,style);
    },
    /****************************************** 绘制图像 END   *********************************************************/

    /****************************************** 图像计算  START ********************************************************/
    /**
     * 计算圆线
     * @param lon 中心点经度
     * @param lat 中心点纬度
     * @param radius 半径（m）
     * @param startAngle
     * @param endAngle
     * @returns {*[]}
     */
    computeCirclularLine(lon, lat, radius, startAngle, endAngle) {
        // 赤道半径,极半径
        var Ea = 6378137,Eb = 6356725;
        var positionArr = [];
        //需求正北是0° cesium正东是0°
        for (var i = parseInt(startAngle); i <=parseInt(endAngle); i++) {
            var dx = radius * Math.sin(i * Math.PI / 180.0);
            var dy = radius * Math.cos(i * Math.PI / 180.0);

            var ec = Eb + (Ea - Eb) * (90.0 - lat) / 90.0;
            var ed = ec * Math.cos(lat * Math.PI / 180);

            var BJD = parseFloat(lon) + parseFloat((dx / ed) * 180.0 / Math.PI);
            var BWD = parseFloat(lat) + parseFloat((dy / ec) * 180.0 / Math.PI);

            positionArr.push(BJD+"");
            positionArr.push(BWD+"");
        }
        return positionArr;
    },
    /**
     * 多边形字符串转线对象
     * @param polygonString
     * @param lon
     * @param lat
     * @returns {*[]}
     */
    polygonStringToLine(polygonString,lon,lat){
        var polygon = [];
        var n = 0;
        var j = polygonString.length/2;
        if(lon && lat){
            polygon[0] = [lon,lat];
            n++;
        }
        for (var i = 0; i < j; i++) {
            polygon[i+n] = [Number(polygonString[i*2]),Number(polygonString[i*2+1])];
        }
        if(lon && lat){
            polygon[0] = [lon,lat];
        }
        return polygon;
    },
    /**
     * 多边形字符串转多边形对象
     * @param polygonString
     * @param lon
     * @param lat
     * @returns {*[][]}
     */
    polygonStringToPolygon(polygonString,lon,lat) {
        var polygon = this.polygonStringToLine(polygonString,lon,lat)
        return [polygon];
    },
    /**
     * 获取对象面积
     * @param polygon {ol.geom.Polygon}
     * @returns {*}
     */
    getArea(polygon){
        return polygon.getArea();
    },
    /**
     * 按球体获取面积
     * @param polygon {ol.geom.Polygon}
     * @returns {string}
     */
    getAreaBySphere(polygon,map){
        map = map == null ? this.map : map;
        // 克隆多边形 --> 转化为EPSG:4326坐标系
        var geom = polygon.clone().transform(map.getView().getProjection(), 'EPSG:4326');
        // 获取克隆多边形坐标
        var coordinates = geom.getLinearRing(0).getCoordinates();
        // 创建半径为6378137.0米的球体 Sphere 5.0 没有这个参数
        var wgs84Sphere = new ol.Sphere(6378137.0);
        // 多边形在球体面积
        var area = Math.abs(wgs84Sphere.geodesicArea(coordinates));
        if (area > 10000) {
            return (Math.round(area / 1000000 * 100) / 100) + ' km²';
        } else {
            return (Math.round(area * 100) / 100) + ' m²';
        }
    },
    /****************************************** 图像计算  END   ********************************************************/

    /**
     * 聚合
     * @param data 点位置数组，格式：[[lon,lat]]
     * @param distance 聚合的距离参数，即当标注间距离小于此值时进行聚合，单位是像素
     * @param styleFun
     * @param map
     * @returns {ol.layer.Vector}
     */
    addCluster(data,distance,styleFun,map){
        map = map == null ? this.map : map;
        distance = distance == null ? 40 : distance;
        var sources = new ol.source.Vector();
        // 插入数据
        for (let dataKey of data) {
            sources.addFeature(new ol.Feature({
                geometry: new ol.geom.Point(dataKey)
            }));
        }
        // 聚合标注数据源
        var clusterSource = new ol.source.Cluster({
            // 聚合的距离参数，即当标注间距离小于此值时进行聚合，单位是像素
            distance: distance,
            // 聚合的数据源，即矢量要素数据源对象
            source: sources
        });
        // 设置样式
        if(styleFun == null){
            styleFun = function (feature, resolution){
                //获取该要素所在聚合群的要素数量
                var size = feature.get('features').length;
                var style = new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: 10,
                        stroke: new ol.style.Stroke({
                            color: '#fff'
                        }),
                        fill: new ol.style.Fill({
                            color: '#d70303'
                        })
                    }),
                    text: new ol.style.Text({
                        text: size.toString(),
                        font: "bold 13px normal",
                        // 文本对齐方向，以线的中心点为基准。 'left', 'right', 'center', 'end' or 'start'. Default is 'center'.
                        textAlign: "center",
                        // 文本底部对齐方向，以线为基准。 'bottom', 'top', 'middle', 'alphabetic', 'hanging', 'ideographic'.
                        textBaseline: "middle",
                        offsetX: 0,
                        offsetY: -12,
                        fill: new ol.style.Fill({
                            color: "#000000"
                        }),
                        stroke: new ol.style.Stroke({color: '#ab13de', width: 2})
                    })
                });
                return [style];
            };
        }
        //加载聚合标注的矢量图层
        var clusters = new ol.layer.Vector({
            source: clusterSource,
            style: styleFun
        });
        // 添加图层
        map.addLayer(clusters);
        return clusters;
    },
    /**
     * 添加图片
     * @param url
     * @param extent
     * @param opacity
     * @param endFun
     * @param errorFun
     * @param map
     * @returns {ol.layer.Image}
     */
    addImage(url,extent,opacity,endFun,errorFun,map){
        map = map == null ? this.map : map;
        if (endFun == null) {
            endFun = function() {
                console.log('图片加载结束！')
            }
        }
        if (errorFun == null) {
            errorFun = function() {
                console.log('图片加载失败！')
            }
        }
        // 制作图层源
        var source = new ol.source.ImageStatic({
            url: url,
            imageExtent: extent,
            // 图片跨域支持
            crossOrigin: ''
        });
        // 图片加载侦听
        source.on('imageloadend', endFun);
        source.on('imageloaderror', errorFun);
        // 新建一个Image对象，并且添加图片资源
        let image = new ol.layer.Image({
            source: source,
            opacity: opacity,
        });
        map.addLayer(image);
        return image
    },
    /**
     * 添加json数据
     * @param url 地址
     * @param style 样式
     * @param projection 坐标系
     * @param map
     */
    addJson(url,style,projection,map){
        map = map == null ? this.map : map;
        projection = projection == null ? this.coordinateDefault : projection;
        style = style == null ? this.styles.json : style;
        map.addLayer(new ol.layer.Vector({
            source: new ol.source.Vector({
                projection: projection,
                url: url, // GeoJSON的文件路径，用户可以根据需求而改变
                format: new ol.format.GeoJSON()
            }),
            style: style
        }))
    },
    /**
     * 添加WMS图层-切片方式
     * @param url 地址
     * @param params 参数
     * @param serverType 类型
     * @param zIndex
     * @param name
     * @param map
     */
    addWMS(url,params,serverType,zIndex,name,map){
        map = map == null ? this.map : map;
        const wms = new ol.layer.Tile({
            name: name,
            source: new ol.source.TileWMS({
                url: url,
                params: params,
                serverType: serverType
            })
        });
        map.addLayer(wms);
        if(zIndex){
            wms.setZIndex(zIndex)
        }
    },
    /**
     * 添加WMS图层-图片方式
     * @param url
     * @param params
     * @param serverType
     * @param zIndex
     * @param name
     * @param map
     */
    addWMSByImage(url,params,serverType,zIndex,name,map){
        map = map == null ? this.map : map;
        const wms = new ol.layer.Image({
            name: name,
            source: new ol.source.ImageWMS({
                url: url,
                params: params,
                serverType: serverType
            })
        });
        map.addLayer(wms);
        if(zIndex){
            wms.setZIndex(zIndex)
        }
    },
    /**
     * 添加Geoserver图层-切片方式
     * @param url
     * @param layerName
     * @param stylesName
     * @param cql_filter
     * @param zIndex
     * @param name
     * @param map
     */
    addGeoserver(url,layerName,stylesName,cql_filter,zIndex,name,map){
        map = map == null ? this.map : map;
        const params = {
            SRS : "EPSG:4326",
            VERSION : "1.1.1"
        }
        if (layerName) {
            params.LAYERS = layerName
        }
        if (stylesName) {
            params.STYLES = stylesName
        }
        if (cql_filter) {
            params.cql_filter = cql_filter
        }
        if (!zIndex && zIndex !== 0) {
            zIndex = map.getLayers().getLength()
        }
        this.addWMS(url,params,'geoserver',zIndex,name,map)
    },
    /**
     * 添加Geoserver图层-图片方式
     * @param url
     * @param layerName
     * @param stylesName
     * @param cql_filter
     * @param zIndex
     * @param name
     * @param map
     */
    addGeoserverByImage(url,layerName,stylesName,cql_filter,zIndex,name,map){
        map = map == null ? this.map : map;
        const params = {
            SRS : "EPSG:4326",
            VERSION : "1.1.1"
        }
        if (layerName) {
            params.LAYERS = layerName
        }
        if (stylesName) {
            params.STYLES = stylesName
        }
        if (cql_filter) {
            params.cql_filter = cql_filter
        }
        if (!zIndex && zIndex !== 0) {
            zIndex = map.getLayers().getLength()
        }
        this.addWMSByImage(url,params,'geoserver',zIndex,name,map)
    },

    // 绘制轨迹
    drawTrajectory(trajectoryData,map){
        map = map == null ? this.map : map;
        // 车辆图层
        var vehicleLayer = new ol.layer.Vector({
            source: new ol.source.Vector()
        });
        // 将图层添加到地图
        map.addLayer(vehicleLayer);

        // 车辆特征
        var trackData0 = trajectoryData[0];
        var vehicleFeature = new ol.Feature({
            geometry: new ol.geom.Point([trackData0[0], trackData0[1]])
        });
        vehicleFeature.setStyle(this.createVehicleStyle(0, trackData0[3]));

        // 航迹坐标
        var trackCoordinates = trajectoryData.map(function (data) {
            return [data[0], data[1]];
        });
        var trackFeature = new ol.Feature({
            geometry: new ol.geom.LineString(trackCoordinates),
        });
        trackFeature.setStyle(new ol.style.Style({
            stroke: new ol.style.Stroke({
                color: '#FF0000',
                width: 2
            })
        }));

        // 添加两个特征
        vehicleLayer.getSource().addFeature(trackFeature);
        vehicleLayer.getSource().addFeature(vehicleFeature);

        var currentIndex = 0;
        const interval = 1000; // 动画更新间隔（毫秒）
        function playTrack() {
            if (currentIndex < trajectoryData.length) {
                var data = trajectoryData[currentIndex];
                var lon = data[0];
                var lat = data[1];
                var direction = data[2];
                var time = data[3];
                var rotation = direction * Math.PI / 180;

                vehicleFeature.setGeometry(new ol.geom.Point([lon, lat]));
                vehicleFeature.setStyle(OpenLayersUtil.createVehicleStyle(rotation, "时间: " + time));

                currentIndex++;
                setTimeout(playTrack, interval);
            }
        }
        playTrack()
    },
    /**
     * 创建车辆样式
     * @param rotation 方向
     * @param timeText 时间
     * @returns {ol.style.Style}
     */
    createVehicleStyle(rotation, timeText) {
        return new ol.style.Style({
            image: new ol.style.Icon({
                src: 'images/icon-arrow.png', // 请替换为你的车辆图标路径
                rotation: rotation,
                rotateWithView: true,
                anchor: [0.5, 1] // 图标锚点设置在底部中心
            }),
            text: new ol.style.Text({
                text: timeText,
                offsetY: 25, // 时间文本与图标的垂直距离
                font: '12px Calibri,sans-serif',
                fill: new ol.style.Fill({ color: '#000' }),
                stroke: new ol.style.Stroke({ color: '#fff', width: 3 })
            })
        });
    }

}


